前言
当你想要在浏览器中实现元素由远到近的动画效果的时候,你可以使用 Three.js 的 CSS3DRenderer 来模拟 3D 变换并将其渲染到 HTML DOM 元素上。
开始
从官方文档的描述中我们可以得知 CSS3DRenderer
的本质是通过CSS3的 transform 属性, 将层级的3D变换应用到DOM元素上,这样就可以直接在 HTML DOM 元素上做出 3D 的效果。
NPM 安装
npm install three
导入项目
import * as THREE from "three";
import { CSS3DRenderer, CSS3DObject } from "three/examples/jsm/renderers/CSS3DRenderer.js";
3D穿梭效果示例
import * as THREE from "three";
import { CSS3DRenderer, CSS3DObject } from "three/examples/jsm/renderers/CSS3DRenderer.js";
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 10000);
const renderer = new CSS3DRenderer();
const objects: CSS3DObject[] = [];
initScene();
animate();
function initScene() {
let sceneContainer = document.getElementById("sceneContainer");
if (!sceneContainer) return;
scene.clear();
camera.position.set(0, 0, 3000);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.domElement.style.position = "absolute";
renderer.domElement.style.top = "0";
sceneContainer.appendChild(renderer.domElement);
for (let i = 0; i < 50; i++) {
createItem(i);
}
}
function createItem(index: number) {
const element = document.createElement("img");
element.style.borderRadius = "50%";
element.style.width = "30px";
element.style.height = "30px";
element.style.background = "gray";
element.id = `item-${index}`;
const cssObject = new CSS3DObject(element);
cssObject.position.set(Math.random() * 200 - 100, Math.random() * 200 - 100, Math.random() * -2000 - 500);
scene.add(cssObject);
objects.push(cssObject);
}
function animate() {
objects.forEach((obj) => {
obj.position.z += 10;
const distance = Math.abs(camera.position.z - obj.position.z);
const scale = Math.max(0.1, 1 - distance / 5000);
obj.element.style.width = `${30 * scale}px`;
obj.element.style.height = `${30 * scale}px`;
obj.element.style.opacity = `${Math.max(0, 1 - distance / 3000)}`;
if (obj.position.z > 3000) {
obj.element.style.opacity = "0";
obj.position.set(Math.random() * 200 - 100, Math.random() * 200 - 100, Math.random() * -2000 - 500);
}
});
renderer.render(scene, camera);
requestAnimationFrame(animate);
}